home *** CD-ROM | disk | FTP | other *** search
/ Commodore Free 31 / Commodore_Free_Issue_31_2009_Commodore_Computer_Club.d64 / c part 2.1 < prev    next >
Text File  |  2023-02-26  |  16KB  |  617 lines

  1. u
  2.  
  3. ************************************
  4. Alternative Programming Languages: C
  5.              Part 2
  6.          By Paul Davis
  7. ************************************
  8.  
  9. Welcome back to this brief look at
  10. cross-development with the C
  11. programming language. I hope you are
  12. finding it interesting and are
  13. inspired to learn more about this
  14. useful language. As always, I welcome
  15. your feedback and have now set up a
  16. blog where you can leave comments on
  17. any of my articles. The links for my
  18. web site and blog can be found at the
  19. end of this article.
  20.  
  21. Last time, I set a small challenge to
  22. write a function that moves a sprite
  23. to any position on the screen. How
  24. did you do? Here is one possible
  25. solution to that problem:
  26.  
  27. void move_sprite(int x, int y)
  28.  
  29.   VIC.spr0_y = y;
  30.   if (x < 256)
  31.   
  32.     VIC.spr_hi_x = 0;
  33.     VIC.spr0_x = x;
  34.   
  35.   else
  36.   
  37.     VIC.spr_hi_x = 1;
  38.     VIC.spr0_x = x - 256;
  39.   
  40.  
  41.  
  42. Bonus points are awarded if you came
  43. up with something along these lines:
  44.  
  45. void move_sprite(int x, int y)
  46.  
  47.   VIC.spr0_y = y;
  48.   VIC.spr0_x = x & 255;
  49.   VIC.spr_hi_x = x / 256;
  50.  
  51.  
  52. Back to this issue and, as promised,
  53. this time we are going to be creating
  54. our very own sprite handling library.
  55. In the process we will learn more
  56. about how to build a C program from
  57. several smaller components and how
  58. these separate parts are compiled and
  59. linked together. We will also
  60. introduce some other tools to make
  61. the development process a little
  62. easier.
  63.  
  64. Getting started
  65.  
  66. We will be using a command line
  67. environment to compile our programs,
  68. so the first thing to do is start the
  69. command prompt/terminal window
  70. application for your particular
  71. operating system. Next, we need to
  72. make sure the environment is properly
  73. configured. If you are running
  74. Windows enter these commands:
  75.  
  76.   cd c:\cc65\tut
  77.   init
  78.  
  79. The 'init.bat' script is available in
  80. the zip file attachment for this
  81. article on my web site. If you
  82. previously set up the environment
  83. permanently in System Properties you
  84. do not need to run this script.
  85.  
  86. Linux and OSX users enter these
  87. commands:
  88.  
  89.   cd /Documents/cc65
  90.   . init.sh
  91.  
  92. Creating a header file
  93.  
  94. Before we jump in and create our
  95. function library, let's take a step
  96. back and see how to create and use a
  97. header file. If you remember from
  98. last time, header files are used to
  99. declare the existence of various
  100. functions, data types and constants
  101. in the C libraries so we can use them
  102. in our programs. There's nothing
  103. particularly special about a header
  104. file, it's just another plain text
  105. file and we can easily create our
  106. own.
  107.  
  108. Many of the programs we have seen so
  109. far contain similar code at the
  110. start. For example we have used the
  111. 'typedef' instruction to create a
  112. type such as 'byte' to represent an
  113. 'unsigned char'. Rather than keep
  114. repeating this code over and over in
  115. every program we write, we can put
  116. the code into a header file and just
  117. include that file in our programs.
  118. Let's try it. Edit a new file called
  119. 'mytypes.h' (OSX users replace
  120. 'notepad' in the command below with
  121. 'edit', Linux users replace it with
  122. your favourite text editor):
  123.  
  124.   notepad mytypes.h
  125.  
  126. Now enter (or copy and paste) the
  127. following code into the file and save
  128. it:
  129.  
  130. typedef unsigned char byte;
  131. typedef unsigned int word;
  132. typedef unsigned char bool;
  133.  
  134. #ifndef TRUE
  135. #define TRUE 1
  136. #define FALSE 0
  137. #endif
  138.  
  139. As is becoming customary, I've
  140. sneaked in some new language features
  141. here. The first couple of typedef
  142. lines should be familiar; they create
  143. the new types for unsigned 8 and 16
  144. bit values, byte and word
  145. respectively. The third typedef is
  146. for a Boolean (true or false) value.
  147. The standard C language doesn't have
  148. a dedicated Boolean type, it simply
  149. treats any zero value as 'false' and
  150. any non-zero value as 'true'. It's
  151. often helpful to create such a type
  152. to make the intent of our programs
  153. clearer. For example, if a function
  154. takes a 'bool' as a parameter, it's
  155. more obvious that you should be
  156. passing in a true or false value. If
  157. that same function just declared its
  158. parameter as a 'byte' it's not so
  159. obvious. As you may have guessed, we
  160. will be making use of this 'bool'
  161. type in our sprite library.
  162.  
  163. The next group of lines create
  164. constants for our new bool type, TRUE
  165. and FALSE. But what's the deal with
  166. the #ifndef part? This instruction is
  167. one of several that C provides for
  168. 'conditional compilation'. The
  169. instructions between that line and
  170. the #endif line will only be compiled
  171. if a certain condition is met. The
  172. '#ifndef' instruction stands for 'if
  173. not defined'. In other words the
  174. whole line means 'compile the
  175. following lines only if TRUE has not
  176. already been defined'. Why would it
  177. already be defined, you ask? It turns
  178. out that making a 'bool' type and the
  179. TRUE/FALSE constants is a fairly
  180. common practice. It's possible that
  181. other header files from other
  182. libraries will have such definitions.
  183. Since C doesn't allow constants to be
  184. re-defined, we use #ifndef as a
  185. precaution so that our header file
  186. doesn't try to define the values
  187. again if they already exist.
  188.  
  189. To test our header file we need to
  190. create a program that uses it. Edit a
  191. new file called 'bool.c' and enter
  192. this program into it:
  193.  
  194. #include <stdio.h>
  195. #include "mytypes.h"
  196.  
  197. void main(void)
  198.  
  199.   byte x = 123;
  200.   word y = 12345;
  201.   bool z = TRUE;
  202.  
  203.   printf("x = %d\n", x);
  204.   printf("y = %d\n", y);
  205.   printf("z = %d\n", z);
  206.   printf("z is %s\n",
  207.          z ? "true":"false");
  208.  
  209.  
  210. Compile the program using the
  211. command:
  212.  
  213.   cl65 bool.c
  214.  
  215. Running the program in the VICE
  216. emulator will print out the numeric
  217. values of the variables along with
  218. the true/false value of the 'z'
  219. variable in words.
  220.  
  221. This program includes our header file
  222. to allow it to use the new types.
  223. Notice how, in the #include line, the
  224. file name is contained in double
  225. quotes rather than 'angled brackets'.
  226. This is important. The brackets tell
  227. C to search for the file in the
  228. compiler's 'include' directory.
  229. Double quotes tell C to search for
  230. the file in the current working
  231. directory.
  232.  
  233. Another new language feature has
  234. crept in here. On the final printf
  235. line, we use what is called the
  236. 'tertiary if operator' represented by
  237. the question mark. This is a very
  238. useful mechanism in C for performing
  239. an 'if' without the full-blown syntax
  240. of the 'if' statement. It has this
  241. form:
  242.  
  243.   condition ? true_value :
  244. false_value
  245.  
  246. The part before the question mark is
  247. a condition, something that has a
  248. true or false result. In this
  249. example, the variable 'z' has such a
  250. value already so the variable itself
  251. is the condition. After the question
  252. mark is the value to use if the
  253. condition was true, in this case we
  254. use the literal string "true". The
  255. value to use when the condition is
  256. false is separated from the true
  257. value by a colon. Here we just use
  258. the literal string "false". The end
  259. result of all this is that when the
  260. printf function is called, the value
  261. of the z variable is tested and if
  262. its value is true, the string "true"
  263. is passed as a parameter, otherwise
  264. the string "false" is passed instead.
  265. This is a much neater solution than
  266. the alternatives using a standard
  267. 'if' statement, such as:
  268.  
  269.   if (z) printf("z is true\n");
  270.   else printf("z is false\n");
  271.  
  272. or:
  273.  
  274.   char *zstr;
  275.   if (z) zstr = "true";
  276.   else zstr = "false";
  277.   printf("z is %s\n", zstr);
  278.  
  279. Learning how to write and use a
  280. header file is the first step towards
  281. creating our function library. Next,
  282. we need a little more understanding
  283. of the how the compiler translates
  284. our C source code into an executable.
  285.  
  286. The compilation process
  287.  
  288. Up until now, we've been using the
  289. 'cl65' command to compile our
  290. programs. This is actually a
  291. convenience command provided by the
  292. cc65 authors to make compiling simple
  293. programs as easy as possible. But now
  294. it's time to learn the individual
  295. steps in the compilation process.
  296.  
  297. To start with, let's create an
  298. 'empty' program. Create a new file
  299. called 'sprtst.c' and enter the
  300. following code into it:
  301.  
  302. void main(void)
  303.  
  304.  
  305.  
  306. Remember from the first article that
  307. a C program must have a main
  308. function, so this represents the
  309. simplest possible 'program' for
  310. testing purposes, one that does
  311. absolutely nothing.
  312.  
  313. Now, we're not going to compile this
  314. using the familiar cl65 command.
  315. Instead we're going to go through the
  316. same steps by hand that cl65 would
  317. automatically do for us. First, we
  318. need to compile the program source
  319. code into assembly language using the
  320. cc65 command as follows:
  321.  
  322.   cc65 -t c64 sprtst.c
  323.  
  324. One thing to note here is that we now
  325. have to specify the target machine
  326. using the '-t c64' option. The cc65
  327. compiler works with many 6502 based
  328. systems and needs to be told which
  329. one we want to use. The cl65 command
  330. automatically assumes c64 by default,
  331. but the individual compilation
  332. commands do not.
  333.  
  334. Once the program has compiled,
  335. Windows users enter this command:
  336.  
  337.   dir sprtst.*
  338.  
  339. OSX and Linux users enter this
  340. command:
  341.  
  342.   ls -l sprtst*
  343.  
  344. This command lists all files called
  345. 'sprtst' with different extensions.
  346. You should see our 'sprtst.c' source
  347. file and a new file created by the
  348. cc65 command called 'sprtst.s'. This
  349. is the result of the C code being
  350. translated to assembly language.
  351.  
  352. The next step is to assemble this
  353. file into machine code using the ca65
  354. assembler. Enter the following
  355. command:
  356.  
  357.   ca65 -t c64 sprtst.s
  358.  
  359. Enter the dir (or ls) command from
  360. before and you will see a new file
  361. 'sprtst.o' in the list. Here's a tip
  362. for anyone who is not familiar with
  363. using a command line environment. You
  364. can repeat previously typed commands
  365. by pressing the cursor up key until
  366. the command you want to run is shown
  367. then pressing the return key to run
  368. it.
  369.  
  370. The output from the assembler is not
  371. a complete program that you can run
  372. on the Commodore. Files with a '.o'
  373. extension are called 'object files'
  374. and they contain, among other things,
  375. machine code fragments. Why create
  376. this intermediate file? Well, it
  377. allows a C program to be built up
  378. from multiple components. You have
  379. already seen that many C functions
  380. are stored in libraries. These
  381. libraries need to be linked together
  382. with our own code to create the
  383. complete executable program. The tool
  384. used to perform this linking is,
  385. unsurprisingly, called a linker and
  386. is run as follows (enter this all on
  387. one line):
  388.  
  389.   ld65 -t c64 -o sprtst c64.o
  390. sprtst.o c64.lib
  391.  
  392. This command is more complex than the
  393. previous ones and requires some
  394. explanation. The '-t' option as usual
  395. indicates we are creating a program
  396. for the c64. The '-o' option tells
  397. the linker the name of the output
  398. file, that is the filename of the
  399. finished executable program. Here we
  400. are calling it 'sprtst'. Following
  401. these options are the names of all
  402. the files that are linked together to
  403. create our program. You will
  404. recognise 'sprtst.o' as our program,
  405. but what are the other files?
  406.  
  407. As mentioned previously, every
  408. program starts at the 'main'
  409. function. This doesn't happen by
  410. magic, there is actually a small
  411. piece of 'startup' code that is
  412. placed at the beginning of every
  413. program that performs some
  414. initialisation such as clearing
  415. memory and then calls the 'main'
  416. function. This 'startup code' is
  417. contained within the file called
  418. 'c64.o' and must be the first file
  419. listed in the link process. The last
  420. file, c64.lib contains those standard
  421. library functions we have been using
  422. all this time. The code for any
  423. functions called by our program will
  424. be copied from this file and linked
  425. into our program.
  426.  
  427. Run the dir (or ls) command again and
  428. you should now see 4 files,
  429. 'sprtst.c', 'sprtst.s', 'sprtst.o'
  430. and finally the executable file
  431. 'sprtst'. You could run this program
  432. if you like but, as you already know,
  433. it doesn't do anything? yet!
  434.  
  435. Okay, I can imagine you're thinking
  436. that's a lot of effort to compile a
  437. program that does nothing! Indeed it
  438. is, and the cl65 command was provided
  439. to remove the need for this effort.
  440. But, bear in mind the goal of this
  441. article is to create a function
  442. library. As you may have already
  443. surmised from what we have just done,
  444. to create a library we need to be
  445. able to create 'object files', and to
  446. do that we need to use the separate
  447. compilation commands.
  448.  
  449. No doubt the thought of repeatedly
  450. typing all those separate commands
  451. isn't appealing. Fear not, we are now
  452. going to take a look at a tool that
  453. can alleviate some of the pain. It's
  454. called 'make'.
  455.  
  456. Makefiles
  457.  
  458. Before I can show you how 'make'
  459. works it needs to be installed on
  460. your computer. OSX and Linux users
  461. are lucky enough to already have it
  462. but Windows users will need to
  463. install a copy. Since the other
  464. operating systems use the gnu
  465. implementation of 'make' we will, for
  466. consistency, also use this on
  467. Windows.
  468.  
  469. The gnu tools are hosted on the
  470. sourceforge web site but I'm going to
  471. take the opportunity to introduce
  472. another useful package called
  473. 'unixutils'. This package contains
  474. many gnu unix tools that have been
  475. compiled natively for Windows, that
  476. is they don't require any other DLLs
  477. or 'unix emulation libraries' to be
  478. installed in order to use them. They
  479. are older versions of the tools but
  480. work well and are easy to install. If
  481. you are more familiar with the gnu
  482. tools and unix libraries for Windows,
  483. feel free to install whatever version
  484. of 'make' you like.
  485.  
  486. Unixutils can be found at
  487. http://sourceforge.net/projects/unxuti
  488.  
  489. ls. Click on the big green download
  490. link, then on the download link of
  491. the latest entry in the list of files
  492. that appears. Finally, click on
  493. UnxUtils.zip to download the file.
  494.  
  495. Next, unzip this file to a temporary
  496. directory and navigate to the
  497. usr\local\wbin directory. In here
  498. locate the 'make.exe' file and copy
  499. it to your c:\cc65\bin directory.
  500. This isn't particularly good
  501. practice, but it's the simplest way
  502. of getting up and running since our
  503. environment is already set up to look
  504. for commands in the cc65\bin
  505. directory. If you are more
  506. experienced with such things, you can
  507. install the entire utils package to a
  508. directory of your choice and add the
  509. 'bin' directory to the 'Path'
  510. environment variable.
  511.  
  512. Now, to test that we can run the
  513. command, enter this line:
  514.  
  515.   make
  516.  
  517. You should get an error message from
  518. 'make' saying it can't find a target
  519. or a makefile. If you get a message
  520. saying that 'make' is not recognised
  521. as a command, ensure that you have
  522. placed the make.exe file in the
  523. c:\cc65\bin directory and try again.
  524.  
  525. Right, OSX and Linux users can join
  526. us again now. So how can 'make' help
  527. us to build our programs? The best
  528. way to explain is by example. We need
  529. to create a new file called
  530. 'makefile' (with no extension). OSX
  531. and Linux users can just create the
  532. file in the usual way, but if you are
  533. using Notepad on Windows there is a
  534. problem. If you entered the command
  535. 'notepad makefile' it would actually
  536. create a new file called
  537. 'makefile.txt'. To get around this,
  538. enter the command with a trailing
  539. 'dot':
  540.  
  541.   notepad makefile.
  542.  
  543. Now enter the following lines into
  544. the makefile. Be very careful here,
  545. the lines containing the commands
  546. (ld65, ca65, cc65) must be indented
  547. using the tab key, not spaces.
  548. Unfortunately, this means cutting and
  549. pasting this text in its entirety
  550. will not work. You can copy a line at
  551. a time, just remember to press tab
  552. before each command.
  553.  
  554. sprtst: sprtst.o
  555.     ld65 -t c64 -o sprtst c64.o
  556. sprtst.o c64.lib
  557.  
  558. sprtst.o: sprtst.s
  559.     ca65 -t c64 sprtst.s
  560.  
  561. sprtst.s: sprtst.c
  562.     cc65 -t c64 sprtst.c
  563.  
  564. You will recognise these commands as
  565. the ones we entered a short while
  566. ago. So let's explain how this file
  567. works.
  568.  
  569. An entry in a makefile is formatted
  570. like this:
  571.  
  572.   target-file: dependent-files
  573.       commands to build target-file
  574.  
  575. A line that starts with a filename
  576. followed by a colon indicates a
  577. 'target' file, that is, a file you
  578. want to create from some other files.
  579. Those other files are listed after
  580. the colon and are known as the
  581. dependents of the target file.
  582. Following this line is one or more
  583. command lines, each indented by a tab
  584. character. When run, these commands
  585. will create the target file from its
  586. dependents.
  587.  
  588. Looking at the makefile we have just
  589. created, we can see that the 'sprtst'
  590. file is dependent on the 'sprtst.o'
  591. object file and uses the ld65 command
  592. to build the program from this file.
  593. The 'sprtst.o' file is, in turn,
  594. dependent on the 'sprtst.s' file and
  595. is created from it with the ca65
  596. command. Finally, the 'sprtst.s' file
  597. is dependent on the 'sprtst.c' file
  598. and is created from it using the cc65
  599. command.
  600.  
  601. As you can see, we have built a
  602. 'chain' of dependencies and
  603. corresponding actions. This is
  604. extremely useful because it allows
  605. 'make' to work out what commands need
  606. to be run whenever changes have been
  607. made to a particular file. Edit the
  608. 'sprtst.c' file and add an include
  609. line to the start of it:
  610.  
  611. #include "mytypes.h"
  612.  
  613. void main(void)
  614.  
  615.          CONTINUED IN PART 2.2
  616.  
  617.